package dao

import (
	"context"
	"fmt"
	"gorm.io/driver/clickhouse"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"proxy_resource_test/config"
	"proxy_resource_test/utils/logging"
	"sync"
	"time"
)

var chDB *gorm.DB

// ClickHouseFactory 实现 DBFactory 接口，用于创建 ClickHouse 连接
type ClickHouseFactory struct {
	once sync.Once
	db   *gorm.DB
}

func NewClickHouseFactory() *ClickHouseFactory {
	return &ClickHouseFactory{}
}

func init() {
	RegisterFactory(NewClickHouseFactory())
}

// Connect 构造 DSN 并调用 gorm.Open 连接 ClickHouse，同时开启 SQL 日志输出
func (c *ClickHouseFactory) Connect(ctx context.Context) error {
	var connErr error
	c.once.Do(func() {
		cfg := config.ClickHouseConfig
		dsn := fmt.Sprintf("clickhouse://%s:%d/%s?username=%s&password=%s&read_timeout=%ds",
			cfg.Host,
			cfg.Port,
			cfg.DBName,
			cfg.User,
			cfg.Password,
			cfg.ReadTimeout,
		)
		dbConfig := &gorm.Config{}
		if config.AppConfig.Env == "dev" {
			dbConfig.Logger = logger.Default.LogMode(logger.Info)
		}
		var err error
		db, err := gorm.Open(clickhouse.Open(dsn), dbConfig)
		if err != nil {
			connErr = fmt.Errorf("ClickHouse 连接失败: %w", err)
			return
		}

		// 拿到底层 *sql.DB，设置连接池
		sqlDB, err := db.DB()
		if err != nil {
			connErr = fmt.Errorf("获取 ClickHouse 底层 DB 失败: %w", err)
			return
		}
		sqlDB.SetMaxIdleConns(cfg.MinIdleConns) // 最小空闲
		sqlDB.SetMaxOpenConns(cfg.MaxOpenConns) // 最大连接数
		sqlDB.SetConnMaxLifetime(time.Duration(cfg.MaxLifetimeSeconds) * time.Second)

		c.db = db
		chDB = db
		logging.Info("ClickHouse 已连接", "dsn", dsn)
	})
	return connErr
}

func (c *ClickHouseFactory) Close() error {
	if c.db == nil {
		return nil
	}
	sqlDB, err := c.db.DB()
	if err != nil {
		return fmt.Errorf("获取 ClickHouse 底层 DB 失败: %w", err)
	}
	if err := sqlDB.Close(); err != nil {
		return fmt.Errorf("ClickHouse 关闭失败: %w", err)
	}
	logging.Info("ClickHouse 已关闭")
	return nil
}

func GetCkDB() *gorm.DB {
	if chDB == nil {
		logging.Error("ClickHouse 未初始化")
	}
	return chDB
}
